# -*- coding:utf-8 -*-
# @Author : felix

# 专门存放关键字的文件，把所有常用的接口请求过程当中的操作都存在在这个位置
# 面向对象的思路


# 考虑 1.发送post，get

"""
可添加@allure.step(“描述信息”)

"""
import requests
import allure
import json
import jsonpath
from PytestApi.apirun_v10.core.globalContext import g_context
import hashlib
import json
from datetime import datetime
from deepdiff import DeepDiff



class KeyWords:

    @allure.step("参数数据: 发送post请求")
    def request_post(self,**kwargs):
        response = requests.post(**kwargs)
        g_context().set_dict("current_response", response)
        # 将响应结果添加到 Allure 报告
        allure.attach(response.text, name='Response', attachment_type=allure.attachment_type.TEXT)

        return response

    @allure.step("参数数据: 发送post请求")
    def request_post_form_urlencoded(self,**kwargs):

        """
        发送post 请求
        :param kwargs:
        :return:
        """
        url = kwargs.get('域名', None)
        params = kwargs.get("URL参数",None)
        headers = kwargs.get("请求头",None)
        data = kwargs.get("请求数据",None)

        requests_data = {
            "url": url,
            "params": params,
            "headers": headers,
            "data": data
        }

        response = requests.post(**requests_data)
        # 将返回的对象加入全局变量中
        g_context().set_dict("current_response", response)
        # 将响应结果添加到 Allure 报告
        allure.attach(response.text, name='Response', attachment_type=allure.attachment_type.TEXT)
        allure.attach(response.url, name='response.url', attachment_type=allure.attachment_type.TEXT)
        allure.attach(response.request.body, name='response.request.body', attachment_type=allure.attachment_type.TEXT)

        return response

    @allure.step("参数数据: 发送post请求")
    def request_post_json(self,**kwargs):

        """
        发送post 请求
        :param kwargs:
        :return:
        """
        url = kwargs.get('域名', None)
        params = kwargs.get("URL参数",None)
        headers = kwargs.get("请求头",None)
        data = kwargs.get("请求数据",None)

        requests_data = {
            "url": url,
            "params": params,
            "headers": headers,
            "json": data
        }

        response = requests.post(**requests_data)
        # 将返回的对象加入全局变量中
        g_context().set_dict("current_response", response)
        # 将响应结果添加到 Allure 报告
        allure.attach(response.text, name='Response', attachment_type=allure.attachment_type.TEXT)

        return response



    @allure.step("参数数据: 发送Get请求")
    def request_get(self, **kwargs):

        url: None = kwargs.get('域名', None)
        params = kwargs.get("URL参数",None)
        headers = kwargs.get("请求头",None)
        data = kwargs.get("请求数据",None)

        requests_data = {
            "url": url,
            "params": params,
            "headers": headers,
            "json": data
        }


        response = requests.get(**requests_data)
        g_context().set_dict("current_response", response)
        # 将响应结果添加到 Allure 报告
        allure.attach(response.text, name='Response', attachment_type=allure.attachment_type.TEXT)
        allure.attach(response.url, name='response.url', attachment_type=allure.attachment_type.TEXT)
        allure.attach(response.request.body, name='response.request.body', attachment_type=allure.attachment_type.TEXT)
        return response

    @allure.step("参数数据: 提取JSON数据并存储到全局变量")
    def ex_jsonData(self,**kwargs):
        """
        提取Json数据
        1. 提取的数据是什么？  ---一般提取的都是响应数据
        2. 提取的表达式是什么？
        3. 提取的下标是什么？
        4. 保存到全局的变量名是什么？

        :param EXVALUE: 提取json的表达式
        :param  INDEX: 下标
        :param VARNAME:  存储到全局变量的变量名
        :return:
        """

        # TODO 1 : 获取响应数据
        response = g_context().get_dict("current_response").json()

        print("对应响应:",response)

        # TODO 2 : 拿到对应的提取表达式
        EXVALUE = kwargs.get('EXVALUE', None)

        # TODO 3 : 拿到对应下标
        INDEX = kwargs.get('INDEX', 0)

        if EXVALUE is None:
            INDEX = 0

        # 提取数据
        ex_data = jsonpath.jsonpath(response, EXVALUE)[INDEX]

        allure.attach(ex_data, name='ex_data',
                      attachment_type=allure.attachment_type.TEXT)

        print(ex_data)

        # TODO 4 : 通过提取的数据存储成对应变量到全局变量中
        g_context().set_dict(kwargs["VARNAME"], ex_data)

        print("--------------------")
        print("全局变量中的数据:",g_context().show_dict())
        allure.attach(str(g_context().show_dict()), name='全局变量中的数据',
                      attachment_type=allure.attachment_type.TEXT)
        print("--------------------")
        return ex_data

    @allure.step("断言处理: 通过响应数据进行断言")
    def assert_text_comparators(self, **kwargs):
        """
        :param EXPECTED:  期望结果
        :param VALUE: 实际结果
        :param OP_STR: 比较运算符: > = <
        :return:
        """
        # 字典 + 匿名函数 : lambda 需要传的参数: 执行的操作
        comparators = {
            # key :value
            # 操作符是A: 执行A
            ">": lambda a,b: a>b,
            ">=": lambda a,b: a>=b,
            "<": lambda a,b: a<b,
            "<=": lambda a,b: a<=b,
            "!=": lambda a,b: a!=b,
            "==": lambda a,b: a==b
        }
        if kwargs["OP_STR"] not in comparators:
            raise ValueError(f"没有改操作方式:{kwargs['OP_STR']}")

        if not comparators[kwargs["OP_STR"]](kwargs["EXPECTED"], kwargs["VALUE"]):
            # 返回是false才会进入
            raise AssertionError(f'期望值:{kwargs["EXPECTED"]} {kwargs["OP_STR"]} 实际值:{kwargs["VALUE"]}')


    # TODO 数据库提取的方法
    @allure.step("参数数据：提取数据库数据并存储")
    def ex_mysqlData(self, **kwargs):
        """
        数据库 : 数据库的名称
        引用变量：数据库要存储的变量名，列表格式
        存储到全局变量：{“变量名_下标”:数据}
        """

        import pymysql
        from pymysql import cursors
        config = {"cursorclass": cursors.DictCursor}
        # 读取全局变量 - 根据选择的数据 读取指定的数据库配置 连接对应的数据库
        db_config = g_context().get_dict("_database")[kwargs["数据库"]]
        config.update(db_config)
        con = pymysql.connect(**config)
        cur = con.cursor()
        cur.execute(kwargs["SQL"])
        rs = cur.fetchall()
        cur.close()
        con.close()
        print("数据库查询结果:", rs)
        var_names = kwargs["引用变量"].split(",")
        result = {}
        for i, data in enumerate(rs, start=1):
            for j, value in enumerate(var_names):
                result[f'{var_names[j]}_{i}'] = data.get(var_names[j])  # 根据变量名称找读取出来的内容
        g_context().set_by_dict(result)



    #TODO，字符串排序
    def generate_sorted_param_string(self,params):
        # 获取参数键列表
        param_keys = list(params.keys())
        # 排序
        param_keys.sort()
        # 构建参数字符串
        param_string = ""
        for key in param_keys:
            value = params[key]
            param_string += key + value
        return param_string

    # TODO 获取sig
    @allure.step("获取sig")
    def get_sig_jd(self,**kwargs):
        # 原始的各个变量值
        # token = "951251e3-e0aa-4e3d-a5bc-570f9e96a25e"
        # app_key = "2b16be5a1276428b8a6a241854e0a007"
        # appSecret = "2e17732b99df42cba3901829e1686c90"
        # format_ = "json"  # 这里修改下变量名，避免和Python内置的format函数冲突
        # v = '1.0'

        # token: None = kwargs.get('token', None)
        # app_key = kwargs.get("app_key",None)
        # appSecret = kwargs.get("appSecret",None)
        # format_ = kwargs.get("format",None)
        # v = kwargs.get("v", None)
        # jd_param_json = kwargs.get("jd_param_json", None)
        # jd_param_json_data = { "jd_param_json": "{'StoreNo': '14226271'}"}

        params = kwargs.get("签名",None)

        # 对应原来的 jd_param_json 内容
        # print("jd_param_json:",jd_param_json)
        # jd_param_json = json.dumps(jd_param_json)

        appSecret = params["appSecret"]
        jd_param_json= params["jd_param_json"]

        # print("jd:",jd_param_json)

        # 获取当前时间戳（以秒为单位，这里示例使用整数类型的时间戳，你可以根据实际需求调整格式等）
        # timeStamp = str(int(datetime.now().timestamp()))
        current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        #current_time = '2025-01-12 16:18:04'

        ct = {"timestamp": current_time}
        params.update(ct)
        params.pop("appSecret")
        allure.attach(str(params), name='params', attachment_type=allure.attachment_type.TEXT)
        # 构建包含各个参数的字典
        # params = {
        #     "token": token,
        #     "app_key": app_key,
        #     "format": format_,
        #     "v": v,
        #     "jd_param_json": jd_param_json,
        #     "timestamp": current_time
        # }

        sorted_param_string = self.generate_sorted_param_string(params)
        print("sortedParamString:", sorted_param_string)

        urlF = appSecret + sorted_param_string + appSecret
        #urlF = '2e17732b99df42cba3901829e1686c90app_key2b16be5a1276428b8a6a241854e0a007formatjsonjd_param_json{"StoreNo":"14226271"}timestamp2025-01-12 16:18:04token951251e3-e0aa-4e3d-a5bc-570f9e96a25ev1.02e17732b99df42cba3901829e1686c90'
        print("urlF: ", urlF)
        allure.attach(urlF, name='urlF', attachment_type=allure.attachment_type.TEXT)

        # 计算MD5签名
        md5_hash = hashlib.md5(urlF.encode()).hexdigest().upper()
        print("MD5: ", md5_hash)

        # TODO 4 : 通过提取的数据存储成对应变量到全局变量中
        g_context().set_dict("sign", md5_hash)
        g_context().set_dict("current_time", current_time)
        g_context().set_dict("jd_param_json", jd_param_json)

        print("--------------------")
        print("全局变量中的数据:", g_context().show_dict())
        allure.attach(str(g_context().show_dict()), name='全局变量中的数据', attachment_type=allure.attachment_type.TEXT)
        print("--------------------")

        return current_time, md5_hash



    # TODO 扩展--全量断言--对比2个json的差异
    @allure.step("参数数据:全量断言--对比2个Json差异")
    def assert_json_DeepDiff(self,**kwargs):
        """
        对比两个json的差异
        :param json1: 期望结果
        :param json2: 实际结果
        :param exclude_paths:需要排除的字段，集合的类型，比如{“id”,...}
        :param ignore_order: 忽略顺序，一般用户有序数据类型，比如列表
        :param ignore_string_case:忽略值的大小写，False
        :return: 当数据没有差异则返回空集合
        """
        json1 = kwargs["json1"]
        json2 = kwargs["json2"]
        exclude_paths = kwargs.get("过滤字段", None)
        ignore_order = kwargs.get("忽略顺序", None)
        ignore_string_case = kwargs.get("忽略大小写", False)
        screen_data = {"exclude_paths": exclude_paths, "ignore_order": ignore_order,
                       "ignore_string_case": ignore_string_case}
        diff = DeepDiff(json1, json2, **screen_data)
        allure.attach(diff.pretty(), name='对比差异',
                      attachment_type=allure.attachment_type.TEXT)
        assert not diff, f"全量断言失败:{diff}"












if __name__ == '__main__':
    kw =KeyWords()
    data = json.dumps({"StoreNo":"14226271"})
    timeStamp, sig = kw.get_sig(jd_param_json=data)

    url = "https://openapi.jddj.com/djapi/storeapi/getStoreInfoByStationNo"




    requests_data = {
        "v": "1.0",
        "format": "json",
        "app_key": "2b16be5a1276428b8a6a241854e0a007",
        "app_secret" : "2e17732b99df42cba3901829e1686c90",
        "token": "951251e3-e0aa-4e3d-a5bc-570f9e96a25e",
        "jd_param_json": data,
        "sign" : sig,
        "timestamp": timeStamp

    }

    print(requests_data)


    response = requests.post(url=url, data=requests_data)
    # 将返回的对象加入全局变量中

    print(response.url)
    print(response.request.body)
    print(response.text)







